home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / PowerPlant / HCmdButtonAttachment 1.1.1 / HCmdButtonAttachment.cp < prev    next >
Encoding:
Text File  |  1997-07-20  |  11.9 KB  |  417 lines  |  [TEXT/CWIE]

  1. /*******************************************************************************\
  2. |                                                                                |
  3. |    HCmdButtonAttachment.cp     ©1997 John C. Daub.  All rights reserved.        |
  4. |                                                                                |
  5. |    See the file "HCmdButtonAttachment README" for full details, instructions,    |
  6. |    changes, licensing agreement, etc.  Due to the important information        |
  7. |    included in that file, if you did not receive a copy of it, please contact    |
  8. |    the author for a copy immediately, before using this code.                    |
  9. |                                                                                |
  10. |    John C. Daub                        <mailto:hsoi@eden.com>                    |
  11. |    <http://www.eden.com/~hsoi/>        <http://www.eden.com/~hsoi/prog.html>    |
  12. |                                                                                |
  13. \*******************************************************************************/
  14.  
  15.  
  16. #ifdef PowerPlant_PCH
  17. #include PowerPlant_PCH
  18. #endif
  19.  
  20.  
  21. #include "HCmdButtonAttachment.h"
  22.  
  23. #include <PP_KeyCodes.h>
  24. #include <LView.h>
  25.  
  26. #ifndef __EVENTS__
  27. #include <Events.h>
  28. #endif
  29.  
  30. #ifndef __CONTROLS__
  31. #include <Controls.h>
  32. #endif
  33.  
  34. #ifndef __TEXTUTILS__
  35. #include <TextUtils.h>
  36. #endif
  37.  
  38.  
  39. #if ( __PowerPlant__ < 0x01608000 ) // version 1.6/CW11
  40.  
  41. //=============================================================================
  42. //    • CreateFromStream                            [static, public]
  43. //=============================================================================
  44. //    Used when registering the class.  Obsolete in more recent versions of
  45. //    PowerPlant, so we conditionally compile it in and out.  If you are using
  46. //    PowerPlant 1.6 (CW11) or higher, you should use the RegisterClass_() macro
  47. //    instead to register your classes.
  48.  
  49. HCmdButtonAttachment*
  50. HCmdButtonAttachment::CreateFromStream(
  51.     LStream        *inStream )
  52. {
  53.     return (new HCmdButtonAttachment(inStream));
  54. }
  55.  
  56. #endif
  57.  
  58.  
  59. //=============================================================================
  60. //    • HCmdButtonAttachment                        [public]
  61. //=============================================================================
  62. //    Parameterized constructor
  63.  
  64. HCmdButtonAttachment::HCmdButtonAttachment(
  65.     PaneIDT        inControlID,
  66.     Uchar        inSpecifiedKey,
  67.     Uint32        inDelay,
  68.     Boolean        inDrawShortcut,
  69.     MessageT    inMessage,
  70.     Boolean        inExecuteHost)
  71.         : LAttachment( inMessage, inExecuteHost ),
  72.         mControl(nil),
  73.         mControlID(inControlID),
  74.         mDrawShortcut(inDrawShortcut),
  75.         mUseSpecifiedKey(inSpecifiedKey != 0),    // if you specify a key, we'll assume you want
  76.                                                 // to use that key.  if you want to use the
  77.                                                 // first letter of the control's descriptor,
  78.                                                 // assign zero to inSpecifiedKey
  79.         mSpecifiedKey(inSpecifiedKey),
  80.         mFlipped(false),
  81.         mOriginalTitle("\p"),
  82.         mMungedTitle("\p"),
  83. //        mWhenToDraw(0),                            // only usefully initialized at the end of the
  84.                                                 // init routine, so skip it here and save some
  85.                                                 // code size.
  86.         mDelay(inDelay)
  87. {
  88.     InitCmdButtonAttachment();
  89. }
  90.  
  91.  
  92. //=============================================================================
  93. //    • HCmdButtonAttachment                        [public]
  94. //=============================================================================
  95. //    LStream constructor
  96.  
  97. HCmdButtonAttachment::HCmdButtonAttachment(
  98.     LStream        *inStream )
  99.         : LAttachment(inStream),
  100.         mControl(nil),
  101.         mFlipped(false),
  102.         mOriginalTitle("\p"),
  103.         mMungedTitle("\p")
  104. //        mWhenToDraw(0)                            // see above comment for why we don't init this
  105. {
  106.     inStream->ReadData( &mControlID, sizeof(mControlID) );
  107.     
  108.     inStream->ReadData( &mUseSpecifiedKey, sizeof(mUseSpecifiedKey) );
  109.     
  110.     // for ease of editing in Constructor, the "Specified key" field
  111.     // is a string of length 1, but since it's a Pascal-style string,
  112.     // 2 bytes are actually stored.  So, we'll read and swallow one dummy
  113.     // character for the length byte.
  114.     
  115.     Uchar dummy;
  116.     inStream->ReadData( &dummy, 1 );
  117.     SignalIf_(dummy == 0); // if the string is zero length, that's bad
  118.     inStream->ReadData( &mSpecifiedKey, sizeof(mSpecifiedKey) );
  119.     
  120.     inStream->ReadData( &mDelay, sizeof(mDelay) );
  121.     inStream->ReadData( &mDrawShortcut, sizeof(mDrawShortcut) );
  122.     
  123.     InitCmdButtonAttachment();
  124. }
  125.  
  126.  
  127. //=============================================================================
  128. //    • ~HCmdButtonAttachment                        [public, virtual]
  129. //=============================================================================
  130. //    Destructor
  131.  
  132. HCmdButtonAttachment::~HCmdButtonAttachment()
  133. {
  134.     // nothing
  135. }
  136.  
  137.  
  138. //=============================================================================
  139. //    • InitCmdButtonAttachment                    [private]
  140. //=============================================================================
  141. //    Private initializer
  142.  
  143. void
  144. HCmdButtonAttachment::InitCmdButtonAttachment()
  145. {
  146.     // see who we are attached to
  147.     
  148.     LView    *theView = dynamic_cast<LView*>(mOwnerHost);
  149.     
  150.     // normally I would check for nil here, but it might be a legal
  151.     // situation.... so we'll contend with it in other ways...
  152.     
  153.     if ( theView != nil ) {
  154.     
  155.         // get the control and save it for later (faster to cache this
  156.         // pointer than to call FindPaneByID() all the time)
  157.         
  158.         SetControl( dynamic_cast<LControl*>(theView->FindPaneByID(GetControlPaneID())) );
  159.         
  160.         // again, no check for nil here... we have other ways.
  161.     }
  162.     
  163.     // get the original control title
  164.     
  165.     if ( (GetControl() != nil) && GetDrawShortcut() ) {
  166.         Str255 theTitle;
  167.         GetControl()->GetDescriptor(theTitle);
  168.         SetOriginalTitle(theTitle);
  169.     }
  170.     
  171.     SetWhenToDraw();
  172.  
  173.     // we only need to repeat if we're going to draw or not
  174.     
  175.     if (GetDrawShortcut()) {
  176.         StartRepeating();
  177.     }
  178. }
  179.  
  180.  
  181. //=============================================================================
  182. //    • ExecuteSelf                                [protected, virtual]
  183. //=============================================================================
  184. //    Does the dirty work of making the "click" happen
  185.  
  186. void
  187. HCmdButtonAttachment::ExecuteSelf(
  188.     MessageT    inMessage,
  189.     void        *ioParam )
  190. {
  191. #pragma unused (inMessage)
  192.  
  193.     // here's one way we deal with nil pointers
  194.     
  195.     if ( GetControl() == nil ) {
  196.         InitCmdButtonAttachment();
  197.     }
  198.     
  199.     // and now we hope we have something...
  200.     
  201.     if ( GetControl() != nil ) {
  202.     
  203.         // get the EventRecord
  204.         EventRecord theMacEvent = (*(EventRecord*)ioParam);
  205.  
  206.         // we only need worry if the cmdKey is held down
  207.         
  208.         if ( theMacEvent.modifiers & cmdKey ) {
  209.  
  210.             // find our our hot key.  we want to do this every time (instead of
  211.             // just caching it) because titles could change on the fly, so we should
  212.             // be responsive.
  213.             
  214.             Uchar    theHotKey = FindHotKey();
  215.  
  216.             // get the key pressed
  217.             
  218.             Uint8 theKeyPress = theMacEvent.message & charCodeMask;
  219.         
  220.             // see if things match up
  221.             if ( LString::CompareIgnoringCase( &theHotKey, &theKeyPress, 1, 1 ) == 0 ) {            
  222.  
  223.                 // we have a winner, so fake the click in the button
  224.                 
  225.                 GetControl()->SimulateHotSpotClick(kControlButtonPart);
  226.             }
  227.         }        
  228.     }
  229. }
  230.  
  231.  
  232. //=============================================================================
  233. //    • SpendTime                                    [public, virtual]
  234. //=============================================================================
  235. //    Used to modify the look of the control title, appending the cmd-key
  236. //    shortcut to the title of the control
  237.  
  238. void
  239. HCmdButtonAttachment::SpendTime(
  240.     const EventRecord    &inMacEvent )
  241. {
  242. #pragma unused(inMacEvent)
  243.  
  244.     // have to put checks in here, lest risk crashing....
  245.     
  246.     if ( GetControl() == nil ) {
  247.         InitCmdButtonAttachment();
  248.     }
  249.     
  250.     if ( GetControl() == nil ) {
  251.         return;
  252.     }
  253.         
  254.     // we'll only do this if we're enabled (and visble), active, and if the cmd-key is
  255.     // held down (this helps prevent modifying a control that wouldn't make sense
  256.     // to modify (e.g. disabled), and also keeps controls in a not-active state
  257.     // (e.g. backgrounded) from being modified)
  258.     
  259.     LControl *theControl = GetControl();
  260.     
  261.     if ( theControl->IsEnabled() &&
  262.             theControl->IsActive() &&
  263.             IsCommandKeyPressed() ) {
  264.         
  265.         // modify the title to have the shortcut appended to it
  266.  
  267.         Uchar    theHotKey = FindHotKey();        
  268.         MungeTitle( theHotKey );
  269.  
  270.         // and if we already displaying the munged title, don't switch it
  271.         // again, to reduce flicker
  272.         
  273.         if ( !GetShowKeyEquiv() ) {
  274.             Str255 theTitle;
  275.             GetMungedTitle(theTitle);
  276.             theControl->SetDescriptor( theTitle );
  277.             SetShowKeyEquiv( true );
  278.         }
  279.  
  280.     } else {
  281.     
  282.         // no cmd-key down, ensure we're looking normal.  and again, only
  283.         // do this if we need to, to reduce flicker
  284.  
  285.         if ( GetShowKeyEquiv() ) {
  286.             Str255 theTitle;
  287.             GetOriginalTitle( theTitle );
  288.             theControl->SetDescriptor( theTitle );
  289.             SetShowKeyEquiv( false );
  290.         }
  291.     }
  292. }
  293.  
  294.  
  295. //=============================================================================
  296. //    • IsCommandKeyPressed                            [public, virtual]
  297. //=============================================================================
  298. //    Looks to see if the command key is held down or not.  We have to use
  299. //    GetKeys() to do this as modifiers don't generate events
  300.  
  301. Boolean
  302. HCmdButtonAttachment::IsCommandKeyPressed()
  303. {
  304.     // get the state of the keyboard
  305.     
  306.     KeyMap    theKeyMap;
  307.     ::GetKeys(theKeyMap);
  308.     
  309.     // see if the command key is held down
  310.     
  311.     if (((Uchar*)theKeyMap)[6] & 0x80) {
  312.     
  313.         // if so, make sure we don't draw until mDelay has passed
  314.         
  315.         if ( ::TickCount() >= GetWhenToDraw() ) {
  316.             return true;
  317.         } else {
  318.             return false;
  319.         }
  320.     } else {
  321.     
  322.         // it's not held down, so keep upping the ante on when to
  323.         // draw so it all works right
  324.         
  325.         SetWhenToDraw();
  326.         return false;
  327.     }
  328. }
  329.  
  330.  
  331. //=============================================================================
  332. //    • MungeTitle                                    [public, virtual]
  333. //=============================================================================
  334. //    Munge the title to display the command key equiv appended to the control
  335. //    title.  This current will take "Fred" and make it "Fred cmd-F".  Override
  336. //    this routine to modify how the title is munged (prepend the key combo, don't
  337. //    use a hyphen to save space, etc.)
  338.  
  339. void
  340. HCmdButtonAttachment::MungeTitle(
  341.     Uchar    inHotKey )
  342. {    
  343.     LStr255 theTitle;
  344.     
  345.     GetOriginalTitle( theTitle );            // start with the original
  346.     theTitle += char_Space;                    // add a space
  347.     theTitle += char_Propeller;                // add the command key
  348.     theTitle += inHotKey;                    // and finally the given key
  349.     
  350.     // and set it internally
  351.     
  352.     SetMungedTitle( theTitle );
  353. }
  354.  
  355.  
  356. //=============================================================================
  357. //    • FindHotKey                                    [public, virtual]
  358. //=============================================================================
  359. //    Based upon internal settings and configuration, determine the
  360. //    magic key/character which we are to look for and act upon
  361.  
  362. Uchar
  363. HCmdButtonAttachment::FindHotKey(
  364.     Boolean        inForceUpper )
  365. {
  366.     Uchar    theHotKey = 0;
  367.     
  368.     if ( GetControl() != nil ) {
  369.         if ( GetUseSpecifiedKey() ) {
  370.             theHotKey = GetHotKey();
  371.         } else {
  372.         
  373.             // get the button's title
  374.             
  375.             Str255    theTitle;
  376.             GetControl()->GetDescriptor(theTitle);                
  377.             theHotKey = theTitle[1];
  378.         }
  379.  
  380.         // make sure the hot key char is uppercase, if desired
  381.         
  382.         if ( inForceUpper && ((theHotKey >= 'a') && (theHotKey <= 'z')) ) {
  383.             ::UppercaseText( (Ptr)&theHotKey, 1, smSystemScript );
  384.         }
  385.     }
  386.     
  387.     return theHotKey;
  388. }
  389.  
  390.  
  391.  
  392. // the following functions are declared inline in the header file. The #pragma
  393. // mark let's them show up in the CW IDE's function popup for ease of navigation
  394. // and reference. :-)
  395.  
  396. #pragma mark HCmdButtonAttachment::GetControl
  397. #pragma mark HCmdButtonAttachment::SetControl
  398. #pragma mark HCmdButtonAttachment::GetControlPaneID
  399. #pragma mark HCmdButtonAttachment::SetControlPaneID
  400. #pragma mark HCmdButtonAttachment::GetDrawShortcut
  401. #pragma mark HCmdButtonAttachment::SetDrawShortcut
  402. #pragma mark HCmdButtonAttachment::GetUseSpecifiedKey
  403. #pragma mark HCmdButtonAttachment::SetUseSpecifiedKey
  404. #pragma mark HCmdButtonAttachment::GetUseFirstTitleChar
  405. #pragma mark HCmdButtonAttachment::SetUseFirstTitleChar
  406. #pragma mark HCmdButtonAttachment::GetHotKey
  407. #pragma mark HCmdButtonAttachment::SetHotKey
  408. #pragma mark HCmdButtonAttachment::GetShowKeyEquiv
  409. #pragma mark HCmdButtonAttachment::SetShowkeyEquiv
  410. #pragma mark HCmdButtonAttachment::GetOriginalTitle
  411. #pragma mark HCmdButtonAttachment::SetOriginalTitle
  412. #pragma mark HCmdButtonAttachment::GetMungedTitle
  413. #pragma mark HCmdButtonAttachment::SetMungedTitle
  414. #pragma mark HCmdButtonAttachment::GetDelay
  415. #pragma mark HCmdButtonAttachment::SetDelay
  416. #pragma mark HCmdButtonAttachment::GetWhenToDraw
  417. #pragma mark HCmdButtonAttachment::SetWhenToDraw